﻿
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;

namespace httpd_client
{
    public class StateObject
    {
        // 客户socket 
        public Socket workSocket = null;
        // 接受buffer大小   
        public const int BufferSize = 2048;
        // 接收buffer   
        public byte[] buffer = new byte[BufferSize];
        // 接受到的数据  
        public StringBuilder sb = new StringBuilder();
        // 接收到的数据
        public byte[] recv_buff = new byte[2 * BufferSize];
        public UInt32 recv_len = 0;
    }
    public class AsynchronousClient
    {
        // The port number for the remote device.   
        public static int port = 10240;
        // The response from the remote device.   
        private static String response = String.Empty;

        public bool connected = false;

        public static Socket StartClient(String server, int port)
        {  
            try
            {
                IPHostEntry ipHostInfo = Dns.GetHostEntry(server);
                AsynchronousClient.port = port;
                IPAddress ipAddress = ipHostInfo.AddressList[0];
                ipAddress = Dns.GetHostAddresses(server)[0];
                IPEndPoint remoteEP = new IPEndPoint(ipAddress, AsynchronousClient.port);
                // 创建 TCP/IP socket.   
                Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                // 连接远端   
                client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
                return client;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                return null;
            }
        }
        public static void close(Socket client)
        {
            try
            {   
                client.Shutdown(SocketShutdown.Both);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        private static void ConnectCallback(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
                // 完成连接过程 
                client.EndConnect(ar);
                Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString());
                thrd_comm_entry_t status = new thrd_comm_entry_t();
                status.type = task_type_t.TYP_CONNECT_TO_SERV;
                status.status = 0;
                status.dir = task_dir_t.DIR_RESPONSE;
                //通知主线程连接完成
                Form_Main.status_mutex.WaitOne();
                Form_Main.status_inlist.Enqueue(status);
                Form_Main.status_mutex.ReleaseMutex();
                Receive(client);
            }
            catch (System.Net.Sockets.SocketException e)
            {
                //捕获错误
                thrd_comm_entry_t status = new thrd_comm_entry_t();
                status.type = task_type_t.TYP_CONNECT_TO_SERV;
                status.status = 1;
                status.dir = task_dir_t.DIR_RESPONSE;
                //通知主线程捕获错误
                Form_Main.status_mutex.WaitOne();
                Form_Main.status_inlist.Enqueue(status);
                Form_Main.status_mutex.ReleaseMutex();
                Console.WriteLine(e.ToString());
            }
            catch (Exception e)
            {
                thrd_comm_entry_t status = new thrd_comm_entry_t();
                status.type = task_type_t.TYP_CONNECT_TO_SERV;
                status.status = 1;
                status.dir = task_dir_t.DIR_RESPONSE;
                //通知主线程捕获错误
                Form_Main.status_mutex.WaitOne();
                Form_Main.status_inlist.Enqueue(status);
                Form_Main.status_mutex.ReleaseMutex();
                Console.WriteLine(e.ToString());
            }
        }
        private static void Receive(Socket client)
        {
            try
            {   
                StateObject state = new StateObject();
                state.workSocket = client;
                // 开始接收数据
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        private static void ReceiveCallback(IAsyncResult ar)
        {
            try
            {  
                StateObject state = (StateObject)ar.AsyncState;
                Socket client = state.workSocket;
                // 接受数据.   
                int bytesRead = client.EndReceive(ar);
                if (bytesRead > 0)
                {
                    //String content = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
                    //state.sb.Append(content);
                    state.buffer.CopyTo(state.recv_buff, state.recv_len);
                    state.recv_len += (UInt32)bytesRead;
                    while(true)
                    {
                        //int index = state.sb.ToString().IndexOf("\r\n\r\n");
                        int n = 0, i;
                        byte[] tmp = new byte[StateObject.BufferSize];
                        for(i =0; i < state.recv_len; i++)
                        {
                            if((state.recv_buff[i] == Encoding.ASCII.GetBytes("\r")[0]) &&
                                (i <= state.recv_len - 4))
                            {
                                if ((state.recv_buff[i + 1] == Encoding.ASCII.GetBytes("\n")[0]) &&
                                    (state.recv_buff[i + 2] == Encoding.ASCII.GetBytes("\r")[0]) &&
                                    (state.recv_buff[i + 3] == Encoding.ASCII.GetBytes("\n")[0]))
                                {
                                    thrd_comm_entry_t item = new thrd_comm_entry_t();
                                    // 对数据包解码
                                    item = Form_Main.bg_message_decode(tmp);
                                    // 将数据放入接收队列
                                    Form_Main.tcp_in_mutex.WaitOne();
                                    Form_Main.tcp_inlist.Enqueue(item);
                                    Form_Main.tcp_in_mutex.ReleaseMutex();
                                    n = 0;
                                    i += 3;
                                }
                                else
                                {
                                    tmp[n++] = state.recv_buff[i];
                                }
                            }
                            else
                            {
                                tmp[n++] = state.recv_buff[i];
                            }
                        }
                        break;
                    }
                }
                //继续接受数据
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        public static void Send(Socket client, byte[] data, int len)
        {
            
            //开始发送数据 
            try
            {
                client.BeginSend(data, 0, len, 0, new AsyncCallback(SendCallback), client);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        public static void Send(Socket client, String data)
        { 
            byte[] byteData = Encoding.UTF8.GetBytes(data);
            //开始发送数据 
            try
            {
                client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        private static void SendCallback(IAsyncResult ar)
        {
            try
            {  
                Socket client = (Socket)ar.AsyncState;
                //完成数据发送  
                int bytesSent = client.EndSend(ar);
                Console.WriteLine("Sent {0} bytes to server.", bytesSent); 
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
    }
}